using System;
using System.Collections.Generic;
using System.Xml;
using System.Net;
using TALoaders;
using TAAlert.CommonUtils;
using System.Diagnostics;

namespace TAAlert.Alerts
{
    class MACDAlert : Alert
    {
        #region Private Members
        private static readonly string N_SHORT_XML = "nShort";
        private static readonly string N_LONG_XML = "nLong";
        private static readonly string N_FAST_XML = "nFast";
        private double emaShort0M;
        private int nShortM;
        private double emaLong0M;
        private int nLongM;
        private double macdSig0M;
        private int nFastM;
        private double price0M;
        private double macdHist0M;
        private DateTime lastHistDateM;
        static private readonly TraceSwitch traceM = new TraceSwitch("MACDAlert", "Debug info for MACD Alert class");
        #endregion

        #region Constructors
        /// <summary>Constructor used with external loader</summary>
        /// <param name="loader">Loader</param>
        /// <param name="ticker">Security ticker</param>
        /// <param name="nShort">short EMA period</param>
        /// <param name="nLong">long EMA period</param>
        /// <param name="nFast">Signal line period</param>
        public MACDAlert(BaseLoader loader, string ticker, int nShort, int nLong, int nFast)
            : base(loader, ticker, StrategyName.MACD)
        {
            Debug.WriteLineIf(traceM.TraceInfo, "-->MACDAlert(" + loader.Loader.ToString() +
                ", " + ticker + ", nShort=" + nShort + ", nLong=" + nLong + ", nFast=" + nFast + ")");
            this.nShortM = nShort;
            this.nLongM = nLong;
            this.nFastM = nFast;
            this.commonConstructor();
        }

        /// <summary>Constructor used from Xml-Code</summary>
        /// <param name="r">XmlReader open with MACD node</param>
        public MACDAlert(XmlReader r)
            : base(r, StrategyName.MACD)
        {
            this.nShortM = r.ReadElementContentAsInt(N_SHORT_XML, "");
            this.nLongM = r.ReadElementContentAsInt(N_LONG_XML, "");
            this.nFastM = r.ReadElementContentAsInt(N_FAST_XML, "");
            r.ReadEndElement();
            this.commonConstructor();
        }

        /// <summary>Common part of all constructors</summary>
        private void commonConstructor()
        {
            DateTime end = DateTime.Now.Date.AddDays(-1);
            DateTime start = end.AddYears(-1);
            SortedList<DateTime, double> hPrice;
            try
            {
                hPrice = loaderM.getHistoricalPrices(this.Ticker, start, end, QuoteType.AdjClose);
            }
            catch (WebException wex)
            {
                throw new WebException("MACDAlert: Cannot load ticker: '" + base.Ticker + "' using loader:" + base.loaderM.Loader + "\n" + wex.Message);
            }

            List<double> macdHistogram = MACDEvaluator.calcMacdHistogram(hPrice.Values, nShortM, nLongM, nFastM, out emaShort0M, out emaLong0M, out macdSig0M);
            this.price0M = hPrice.Values[hPrice.Count-1];
            this.lastHistDateM = hPrice.Keys[hPrice.Count - 1];
            this.macdHist0M = macdHistogram[hPrice.Count - 1];
            Debug.WriteLineIf(traceM.TraceVerbose, " Constructed " + this.Description + ", price0=" + price0M + ", lastHistDateM=" + lastHistDateM.ToShortDateString() +
                ", emaShort0=" + emaShort0M.ToString(".##") + ", emaLong0=" + emaLong0M.ToString(".##") + ", macdHist0M=" + macdHist0M.ToString(".##"));
        }
        #endregion

        #region Public Methods
        /// <summary>Evaluate latest MACD alert based on the latest price</summary>
        /// <param name="info">Output parameter with calculation details</param>
        /// <returns>Buy/Sell/Neutral signal based on MACD</returns>
        public override Signal evalAlert(out string[] info)
        {
            string timeStamp;
            double price1 = loaderM.getLastPrice(this.Ticker, out timeStamp);
            double emaShort1, emaLong1, macdSig1;
            double macdHist = MACDEvaluator.calcMacdHistogram(price1, nShortM, emaShort0M, out emaShort1, nLongM, emaLong0M, out emaLong1, nFastM, macdSig0M, out macdSig1);
            
            info = new string[13];
            info[0] = string.Format("Price = {0:.####}       (as of {1})", price1, timeStamp);
            info[1] = string.Format("emaShort({0}) = {1:.####}", nShortM, emaShort1);
            info[2] = string.Format("emaLong({0}) = {1:.####}", nLongM, emaLong1);
            info[3] = string.Format("macdLine = {0:.####}", (emaShort1 - emaLong1));
            info[4] = string.Format("macdSignal = {0:.####}", macdSig1);
            info[5] = string.Format("macdHist = {0:.####}", macdHist);
            info[6] = "Old Signal = " + this.oldAlert();
            info[7] = string.Format("Old Price = {0:.####}   (as of {1})", price0M, lastHistDateM.ToShortDateString());
            info[8] = string.Format("Old emaShort({0}) = {1:.####}", nShortM, emaShort0M);
            info[9] = string.Format("Old emaLong({0}) = {1:.####}", nLongM, emaLong0M);
            info[10] = string.Format("Old macdLine = {0:.####}", (emaShort0M - emaLong0M));
            info[11] = string.Format("Old macdSignal = {0:.####}", macdSig0M);
            info[12] = string.Format("Old macdHist = {0:.####}", macdHist0M);

            return MACDEvaluator.macdSignal(macdHist);
        }

        /// <summary>Evaluate yesterday's alert</summary>
        /// <returns>Return alert based on yesterday's prices</returns>
        public override Signal oldAlert()
        {
            return MACDEvaluator.macdSignal(this.macdHist0M);
        }

        public override void writeXml(XmlWriter writer)
        {
            base.writeXml(writer);
            writer.WriteElementString(N_SHORT_XML, nShortM.ToString());
            writer.WriteElementString(N_LONG_XML, nLongM.ToString());
            writer.WriteElementString(N_FAST_XML, nFastM.ToString());
        }

        public override string Description
        {
            get
            {
                return string.Format("{0,-8}: nShort={1,-8}, nLong={2,-8}, nFast={3,-8}", base.XmlName, nShortM, nLongM, nFastM);
            }
        }
        #endregion
    }
}
